#ifndef MONTE_CARLO_H_
#define MONTE_CARLO_H_

#include "general.h"
#include <stdlib.h>
#include <time.h>
#include <limits.h>

typedef struct drand48_data drand48_data;

/* Número de pontos calculados por iteração */
#define POINTS 1000000

/* Quantidade de threads para calcular o valor de m em ITS iterações */
#define NTHREADS 100

/* Número máximo de ITS iterações */
#define MAX_ITS 5000

/* Número máximo de iteraçãoes para a forma concorrente */
#define MAX_ITS_CONC MAX_ITS/NTHREADS

typedef struct
{
    int *i; /* Iteração atual do algoritmo */
    mpz_t m[2]; /* Quantidade de pontos dentro da circunferência */
    struct drand48_data status;  /* Semente geradora de números aleatórios */
} mc_count;

typedef struct
{
    int i; /* Iteração atual do algoritmo */
    mpz_t n; /* Quantidade de pontos calculados */
    mc_count c[NTHREADS]; /* Estruturas para cada thread de contagem */
    mpf_t pi[2]; /* Pi */
    int stop; /* Flag utilizada para parar o algoritmo quando houver convergência */
} mc_param; /* Parâmetros do algoritmo de Monte Carlo concorrente */

/* Retorna um número aleatório entre 0 e RAND_MAX */
double mc_random_number(struct drand48_data *status);

/* Calcula dois números aleatórios e verifica se eles estão dentro de 1/4 da circunferência */
int mc_is_inside_circle(struct drand48_data *status);

/* Calcula a quantidade de pontos dentro da circunferência de ITS pontos aleatórios */
unsigned int mc_number_of_points_in_circle(struct drand48_data *status);

/* Calcula o valor de pi */
void mc_pi_value(mpf_t pi, mpz_t n, mpz_t m);

/* Inicializa os parâmetros de Monte Carlo */
void mc_init_param(mc_param *p);

/* Limpa os parâmetros de Monte Carlo */
void mc_clear_param(mc_param *p);

/* Algoritmo sequencial de Monte Carlo */
void monte_carlo(mpf_t pi, long *it);

/* Algoritmo concorrente de Monte Carlo */

void monte_carlo_conc(mpf_t pi, long *it);
/* Função da thread para calcular números aleatórios e fazer a contagem de m */

void *mct_calculate_points(void *arg);

/* Função da thread que calcula o Pi e verifica convergência */
void *mct_calculate_pi(void *arg);

#endif /* MONTE_CARLO_H_ */
